/****

    activequant - activestocks.eu

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	
	contact  : contact@activestocks.eu
    homepage : http://www.activestocks.eu

****/
package org.activequant.data.util.converter;

import org.activequant.core.domainmodel.SeriesSpecification;
import org.activequant.core.domainmodel.data.Candle;
import org.activequant.core.domainmodel.data.TradeIndication;
import org.activequant.core.domainmodel.data.TradeIndicationSeries;
import org.activequant.core.types.TimeFrame;
import org.activequant.data.retrieval.ICandleSeriesSource;
import org.activequant.data.retrieval.ITradeIndicationSeriesSource;
import org.apache.log4j.Logger;

/**
 * Converts CandleSeries to TradeIndicationSeries. Request to fetch TradeIndications
 * is converted to one or more requests to fetch Candles, then TradeIndications are generated
 * from Candles, using an external strategy.
 * <br/>
 * CandleToTradeIndicationSeriesConverter implements ITradeIndicationSeriesSource. Holds the following associated variables:
 * <ul>
 * <li>candleSeriesSource(ICandleSeriesSource)</li>
 * <li>conversion(ICandleToTradeIndicationConversion)</li>
 * <li>timeFrame(TimeFrame)</li>
 * </ul>
 * <b>History:</b><br>
 *  - [09.30.2008] Created (Mike Kroutikov)<br>
 *
 *  @author Mike Kroutikov
 */
public class CandleToTradeIndicationSeriesConverter implements ITradeIndicationSeriesSource {
	
	private final Logger log = Logger.getLogger(getClass());
	/**
	 * private final ICandleSeriesSource candleSeriesSource;
	 */
	private final ICandleSeriesSource candleSeriesSource;
	/**
	 * private ICandleToTradeIndicationConversion conversion = new LinearCandleToTradeIndicationConversion();
	 */
	private ICandleToTradeIndicationConversion conversion = new LinearCandleToTradeIndicationConversion();
	/**
	 * private TimeFrame timeFrame = TimeFrame.day();
	 */
	private TimeFrame timeFrame = TimeFrame.day();
	/**
	 * constructs a CandleToTradeIndicationSeriesConverter (implements ITradeIndicationSeriesSource) using the given source(ICandleSeriesSource) to set its
	 * associated candleSeriesSource(ICandleSeriesSource)
	 * @param source
	 */
	public CandleToTradeIndicationSeriesConverter(ICandleSeriesSource source) {
		this.candleSeriesSource = source;
	}
	/**
	 * returns a TradeIndicationSeries by converting fetched Candles for the given seriesSpecification(SeriesSpecification) for the associated timeFrame(TimeFrame) period.<br/>
	 * The associated candleSeriesSource(ICandleSeriesSource) is used to fetch the Candles and then the associated conversion(ICandleToTradeIndicationConversion)
	 * is used to convert each Candle into a series of TradeIndications.
	 */
	public TradeIndicationSeries fetch(SeriesSpecification seriesSpecification) throws Exception {
		// passed seriesSpecification is not required to have timeFrame set
		// (or may have time frame of TICK set), because we are requesting
		// trade indication series. But candle series source
		// requires time frame to be set correctly. Do it here.
		SeriesSpecification candleSpec = new SeriesSpecification(seriesSpecification);
		candleSpec.setTimeFrame(timeFrame);

		final TradeIndicationSeries ts = new TradeIndicationSeries(seriesSpecification);
		
		// care has to be taken to keep Series convention of
		// "reverse" ordering (newest event comes first). Hence
		// the "index" logic below
		
		log.info("fetching candles: " + candleSpec);
		for(Candle candle : candleSeriesSource.fetch(candleSpec)) {
			int index = ts.size();
			for(TradeIndication ti : conversion.convert(candle)) {
				ts.add(index, ti);
			}
		}
		
		return ts;
	}
	/**
	 * returns a TradeIndicationSeries[] by converting fetched Candles for each of the given seriesSpecification(SeriesSpecification...) for the associated timeFrame(TimeFrame) period.<br/>
	 * The associated candleSeriesSource(ICandleSeriesSource) is used to fetch the Candles and then the associated conversion(ICandleToTradeIndicationConversion)
	 * is used to convert each Candle into a series of TradeIndications.
	 * @param seriesSpecification
	 * @return
	 * @throws Exception
	 */
	public TradeIndicationSeries[] fetch(SeriesSpecification... seriesSpecification) throws Exception {
		TradeIndicationSeries [] out = new TradeIndicationSeries[seriesSpecification.length];
		for(int i = 0; i < out.length; i++) {
			out[i] = fetch(seriesSpecification[i]);
		}
		
		return out;
	}
	
	/**
	 * Determines the time interval of the candles. 
	 * Default value is 1 day.<br/>
	 * returns the associated timeFrame(TimeFrame)
	 * @return time frame.
	 */
	public TimeFrame getTimeFrame() { 
		return timeFrame;
	}

	/**
	 * Sets the candle time frame.<br/>
	 * sets the associated timeFrame(TimeFrame) with the given val(TimeFrame)
	 * @param val time frame.
	 */
	public void setTimeFrame(TimeFrame val) { 
		timeFrame = val;
	}
	
	/**
	 * Strategy that drives the conversion from candles to trade indications.<br/>
	 * returns the associated conversion(ICandleToTradeIndicationConversion)
	 * @return conversion strategy.
	 */
	public ICandleToTradeIndicationConversion getConversion() {
		return conversion;
	}
	
	/**
	 * Conversion strategy.<br/>
	 * sets the associated conversion(ICandleToTradeIndicationConversion) with the given val(ICandleToTradeIndicationConversion)
	 * @param val conversion strategy.
	 */
	public void setConversion(ICandleToTradeIndicationConversion val) {
		conversion = val;
	}
}